using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using NUnit.Framework;
using ProjectEuler.Core.Helpers;

namespace ProjectEuler.Core
{
    public class Problem62 : IProjectEulerProblem
    {
        public int Number
        {
            get { return 62; }
        }

        public string Description
        {
            get { return "Find the smallest cube for which exactly five permutations of its digits are cube"; }
        }

        public string Answer
        {
            get { return FindSmallestCubeWithNPermutations(5).ToString(); }
        }

        protected BigInteger FindSmallestCubeWithNPermutations(int n)
        {
            var map = new List<Cube>();
            var i = 1;
            while (true)
            {
                var cube = new Cube(i);
                var sameSignature = map.FirstOrDefault(c => c.SortedDigits == cube.SortedDigits);
                if (sameSignature != null)
                {
                    sameSignature.Count++;
                    if (sameSignature.Count == n)
                    {
                        return sameSignature.Value;
                    }
                }
                else
                {
                    map.Add(cube);
                }
                i++;
            }
        }

        public class Cube
        {
            public Cube(int cubeRoot)
            {
                Value = BigInteger.Pow(cubeRoot, 3);
                SortedDigits = SortDigits(Value);
                Count = 1;
            }

            public int Count { get; set; }
            public string SortedDigits { get; set; }
            public BigInteger Value { get; private set; }

            private static string SortDigits(BigInteger cube)
            {
                var digits = cube.ToString().Atomize();
                var sorted = digits.OrderBy(d => d);
                return string.Join("", sorted);
            }
        }
    }

    [TestFixture]
    public class Problem62Tests : Problem62
    {
        [Test]
        public void Two_cube_permutations_should_have_the_same_SortedDigits()
        {
            var cube1 = new Cube(345);
            var cube2 = new Cube(384);
            var cube3 = new Cube(405);

            Assert.That(cube1.SortedDigits, Is.EqualTo(cube2.SortedDigits));
            Assert.That(cube2.SortedDigits, Is.EqualTo(cube3.SortedDigits));
            Assert.That(cube3.SortedDigits, Is.EqualTo(cube1.SortedDigits));
        }

        [Test]
        public void Can_find_smallest_cube_with_3_permutations()
        {
            var p = FindSmallestCubeWithNPermutations(3);
            Assert.AreEqual(p, new BigInteger(41063625));
        }
    }
}